package com.tang.johnzer.logcat_viewer

import android.os.Handler
import android.os.Looper
import android.util.Log
import androidx.annotation.NonNull

import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.EventChannel.StreamHandler
import io.flutter.plugin.common.EventChannel.EventSink
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader

/** LogcatViewerPlugin */
class LogcatViewerPlugin: FlutterPlugin, MethodCallHandler,  EventChannel.StreamHandler {
  /// The MethodChannel that will the communication between Flutter and native Android
  ///
  /// This local reference serves to register the plugin with the Flutter Engine and unregister it
  /// when the Flutter Engine is detached from the Activity
  private lateinit var channel : MethodChannel
  private lateinit var eventChannel: EventChannel
  private var eventSink: EventChannel.EventSink? = null
  private var stop : Boolean = false

  override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
    channel = MethodChannel(flutterPluginBinding.binaryMessenger, "LogcatViewerPlugin/controrller")
    channel.setMethodCallHandler(this)

    eventChannel = EventChannel(flutterPluginBinding.binaryMessenger, "LogcatViewerPlugin/listen")
    eventChannel.setStreamHandler(this)
  }

  override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
    if (call.method == "startLogInfo") {
//      result.success(startLogs())
//      startLogs()
      Thread{
        runLogcatSubscriber()
      }.start()
    } else if (call.method == "stopLogInfo") {
      stop = true
    } else {
      result.notImplemented()
    }
  }

  private fun startLogs(): String? {
    return try {
      val process: Process = Runtime.getRuntime().exec("/system/bin/logcat -b main")
      val bufferedReader = BufferedReader(InputStreamReader(process.inputStream))
      val log = StringBuilder()
      var line: String?
      while (bufferedReader.readLine().also { line = it } != null) {
        log.append(line)
      }
      log.toString()
    } catch (e: IOException) {
      "EXCEPTION$e"
    }
  }

  private fun runLogcatSubscriber() {
    var process: Process? = null

    //Execute logcat system command
    try {
      process = Runtime.getRuntime().exec("/system/bin/logcat -b main")
    } catch (e: IOException) {
//      sendMessage(MSG_LOGCAT_RUN_FAILURE)
    }

    //Read logcat log entries
    val reader: BufferedReader
    try {
      reader = BufferedReader(InputStreamReader(process!!.inputStream))
      var logEntry: String

      //Till request to kill thread is not received, keep reading log entries
      while (!stop) {
        //Read log entry.
        logEntry = reader.readLine()

        //Send log entry to view.
        sendEventToStream(logEntry)

        //If recording is on, save log entries in mRecordingData in order to save them
        // after every LOG_SAVING_INTERVAL interval
//        if (TextUtils.isEmpty(mFilterText) ||
//          !TextUtils.isEmpty(mFilterText) && logEntry.toLowerCase()
//            .contains(mFilterText.toLowerCase())
//        ) {
//          mRecordingData.add(logEntry)
//        }
      }
      Log.d("LOG_TAG", "Preparing to terminate LogcatRunnable thread")

      //Release resources
      reader.close()
      process.destroy()
    } catch (e: IOException) {
      //Fail to read logcat log entries
    }
    Log.d("LOG_TAG", "Terminating LogcatRunnable thread")
    return
  }


  //推送消息给Event数据流，flutter层负责监听数据流
  private fun sendEventToStream(data: String) {
    Handler(Looper.getMainLooper()).post {
      eventSink?.success(data)
    }
  }

  override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
    channel.setMethodCallHandler(null)
  }

  override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
    // eventChannel 建立连接
    eventSink = events
  }

  override fun onCancel(arguments: Any?) {
    eventSink = null
  }

}
